﻿// (c) Copyright 2013 Mike Riedel.
// This source is subject to the Microsoft Public License (Ms-PL).
// All other rights reserved.

using System;
using System.IO;
using FreshMeat.Storage;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Storage.Core.Test
{
   [TestClass]
   public class FileLocatorTest
   {
      // ReSharper disable ObjectCreationAsStatement

      [TestMethod]
      [ExpectedException(typeof(ArgumentNullException))]
      public void NullFileSystemThrows()
      {
         new FileLocator<int>(null);
      }

      [TestMethod]
      public void DefaultExtensionIsCorrect()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);
         var locator = new FileLocator<int>(fileSystem);

         Assert.AreEqual(".xml", locator.Extension);
      }

      [TestMethod]
      [ExpectedException(typeof(ArgumentOutOfRangeException))]
      public void ExtensionCantBeEmpty()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);

         // should throw exception because extension is empty
         new FileLocator<int>(fileSystem, false, "");
      }

      [TestMethod]
      [ExpectedException(typeof(ArgumentOutOfRangeException))]
      public void ExtensionCantBeDotByItself()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);

         // should throw exception because extension is just "."
         new FileLocator<int>(fileSystem, false, ".");
      }

      [TestMethod]
      public void ExtensionWithoutDotHasOneAdded()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);

         // should throw exception because extension is empty
         var locator = new FileLocator<int>(fileSystem, false, "ext");

         Assert.AreEqual(".ext", locator.Extension, "Leading dot should have been added.");
      }

      [TestMethod]
      public void ExtensionWithLeadingDotIsUsedUnchanged()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);

         var locator = new FileLocator<int>(fileSystem, false, ".ext");

         Assert.AreEqual(".ext", locator.Extension, "Extension should have been used as-is.");
      }


      [TestMethod]
      public void BaseFolderIsCreated()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);
         Assert.IsFalse(Directory.Exists(rootFolder), "Should not exist before constructor is called.");

         new FileLocator<int>(fileSystem);

         Assert.IsTrue(Directory.Exists(rootFolder), "Should exist after constructor is called.");
      }

      [TestMethod]
      public void GetPathIsRelative()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);
         var locator = new FileLocator<int>(fileSystem);

         var path = locator.GetPath(1);

         Assert.IsFalse(path[0] == FreshMeat.Storage.Path.FolderSeparatorChar, "Should not be an absolute path.");
      }

      [TestMethod]
      public void GetPathIsDifferentForEachId()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);
         var locator = new FileLocator<int>(fileSystem);

         var path1 = locator.GetPath(1);
         var path2 = locator.GetPath(2);
         var path3 = locator.GetPath(3);
         var path4 = locator.GetPath(4);

         Assert.AreNotEqual(path1, path2, "Paths should not be the same.");
         Assert.AreNotEqual(path1, path3, "Paths should not be the same.");
         Assert.AreNotEqual(path1, path4, "Paths should not be the same.");
         Assert.AreNotEqual(path2, path3, "Paths should not be the same.");
         Assert.AreNotEqual(path2, path4, "Paths should not be the same.");
         Assert.AreNotEqual(path3, path4, "Paths should not be the same.");
      }

      [TestMethod]
      public void GetIdWorks()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);
         var locator = new FileLocator<int>(fileSystem);
         var path1 = locator.GetPath(1);
         var path2 = locator.GetPath(2);
         var path3 = locator.GetPath(3);
         var path4 = locator.GetPath(4);

         var id1 = locator.GetId(path1);
         var id2 = locator.GetId(path2);
         var id3 = locator.GetId(path3);
         var id4 = locator.GetId(path4);

         Assert.AreEqual(1, id1, "GetId returned wrong value.");
         Assert.AreEqual(2, id2, "GetId returned wrong value.");
         Assert.AreEqual(3, id3, "GetId returned wrong value.");
         Assert.AreEqual(4, id4, "GetId returned wrong value.");
      }

      [TestMethod]
      public void UsesCustomParsingFunction()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);
         var called = 0;
         var locator = new FileLocator<int>(fileSystem, idParser: text =>
                                                   {
                                                      called++;
                                                      return int.Parse(text);
                                                   });

         locator.GetId("1");
         locator.GetId("2");
         locator.GetId("3");

         Assert.AreEqual(3, called, "Custom func should have been called each time.");
      }

      [TestMethod]
      public void GetTempIsRelative()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);
         var locator = new FileLocator<int>(fileSystem);
         var path = locator.GetPath(1);

         var temp = locator.GetTempName(path);

         Assert.IsFalse(temp[0] == FreshMeat.Storage.Path.FolderSeparatorChar, "Should not be an absolute path.");
      }

      [TestMethod]
      public void GetTempIsDifferentEveryTime()
      {
         var rootFolder = GetFolder();
         var fileSystem = new FileSystem(rootFolder);
         var locator = new FileLocator<int>(fileSystem);
         var path1 = locator.GetPath(1);
         var path2 = locator.GetPath(2);
         var path3 = locator.GetPath(3);
         var path4 = locator.GetPath(4);

         var temp1 = locator.GetTempName(path1);
         var temp2 = locator.GetTempName(path2);
         var temp3 = locator.GetTempName(path3);
         var temp4 = locator.GetTempName(path4);

         Assert.AreNotEqual(temp1, temp2, "Paths should not be the same.");
         Assert.AreNotEqual(temp1, temp3, "Paths should not be the same.");
         Assert.AreNotEqual(temp1, temp4, "Paths should not be the same.");
         Assert.AreNotEqual(temp2, temp3, "Paths should not be the same.");
         Assert.AreNotEqual(temp2, temp4, "Paths should not be the same.");
         Assert.AreNotEqual(temp3, temp4, "Paths should not be the same.");
      }

      // ReSharper restore ObjectCreationAsStatement

      string GetFolder()
      {
         return System.IO.Path.Combine(TestContext.TestDir, System.IO.Path.GetRandomFileName());
      }

      // ReSharper disable MemberCanBePrivate.Global
      // ReSharper disable UnusedAutoPropertyAccessor.Global
      public TestContext TestContext { get; set; }
      // ReSharper restore UnusedAutoPropertyAccessor.Global
      // ReSharper restore MemberCanBePrivate.Global
   }
}
